use std::mem;

#[derive(Debug)]
struct Point {
    x: f64,
    y: f64,
}

impl Point {
    fn origin() -> Point {
        Point { x: 0.0, y: 0.0 }
    }
    fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }
}

fn main() {
    let point = Point::new(1.0, 2.0);
    let point1 = Point { x: 2.0, y: 2.2 };

    println!("{:?}", point);
    println!("{:?} ({}, {})", point1, point1.x, point1.y);
    println!("{:?}", Point::origin());

    /*
    闭包
    */
    fn add_one(i: i32) -> i32 {
        i + 1
    }
    let closure_annotated = |i: i32| -> i32 { i + 1 };
    let closure_inferred = |i: i32| i + 1;
    let one = || 1;

    let i = 1;
    println!("add_one: {}", add_one(i));
    println!("closure_annotated: {}", closure_annotated(i));
    println!("closure_inferred: {}", closure_inferred(i));
    println!("closure returning one: {}", one());

    // 闭包优先通过引用捕获变量，并且仅在需要时降级

    let color = String::from("green");
    let print = || println!("color: {}", color);
    print();

    // 闭包调用后，还可以引用和移动color
    let _reborrow = &color;
    print();
    let _color_moved = color;
    // color已被移动
    // println!("color: {}", color);

    let mut count = 0;
    let mut inc = || {
        count += 1;
        println!("count: {}", count);
    };

    inc();
    inc();

    let _count_reborrowed = &mut count;

    println!("reborrow the count: {:?}", _count_reborrowed);

    let movable = Box::new(3);

    let consume = || {
        println!("movable: {:?}", movable);
        mem::drop(movable);
    };

    consume();
    // consume(); //movable已被释放

    // 使用move关键词，强制关闭闭包的参数引用，让闭包获取参数的所有权。
    let haystack = vec![1, 2, 3];
    let contains = move |needle| haystack.contains(needle);
    println!("{}", contains(&1));
    println!("{}", contains(&4));

    // 这里haystack变量已被闭包移动，闭包拥有所有权。删除"move",使用借用可以在此处继续访问。
    // println!("There're {} elements in vec", haystack.len());

    /*
    闭包作为参数输入
    */
    // Fn , FnMut, FnOnce
    fn apply<F>(f: F)
    where
        F: FnOnce(),
    {
        f();
    }

    fn apply_to_3<F>(f: F) -> i32
    where
        F: Fn(i32) -> i32,
    {
        f(3)
    }

    let greeting = "hello";
    let mut farewell = "goodbye".to_owned();

    let diary = || {
        println!("I said {}.", greeting);

        farewell.push_str("!!!");
        println!("Then I screamed {}.", farewell);
        println!("Now I can sleep. zzzzz");

        mem::drop(farewell);
    };

    apply(diary);

    let double = |x| 2 * x;

    println!("3 doubled: {}", apply_to_3(double));

    // 闭包/函数 作为输入
    fn call_me<F: Fn()>(f: F) {
        f();
    }

    fn function() {
        println!("I'm a function!");
    }

    let closure = || println!("I'm a closure!");

    call_me(closure);
    call_me(function);

    // 闭包作为输出
    {
        fn create_fn() -> impl Fn() {
            let text = "Fn".to_owned();

            move || println!("This is a: {}", text)
        }

        fn create_fnmut() -> impl FnMut() {
            let text = "FnMut".to_owned();

            move || println!("This is a: {}", text)
        }

        fn create_fnonce() -> impl FnOnce() {
            let text = "FnOnce".to_owned();

            move || println!("This is a: {}", text)
        }

        let fn_plain = create_fn();
        let mut fn_mut = create_fnmut();
        let fn_once = create_fnonce();

        fn_plain();
        fn_mut();
        fn_once();

        let vec1 = vec![1, 2, 3];
        let vec2 = vec![4, 5, 6];

        println!("2 in vec1: {}", vec1.iter().any(|&x| x == 2));
        println!("2 in vec2: {}", vec2.into_iter().any(|x| x == 2));
        {
            let vec1 = vec![1, 2, 3];
            let vec2 = vec![4, 5, 6];
            let mut iter = vec1.iter();
            let mut into_iter = vec2.into_iter();
            println!("Find 2 in vec1: {:?}", iter.find(|&&x| x == 2));
            println!("Find 2 in vec2: {:?}", into_iter.find(|&x| x == 2));
        }
        let index_of_first_even_number = vec1.iter().position(|&x| x % 2 == 0);
        println!("{:?}", index_of_first_even_number);
        let index_of_first_negative_number = vec1.into_iter().position(|x| x < 0);
        println!("{:?}", index_of_first_negative_number);

        let array1 = [1, 2, 3];
        let array2 = [4, 5, 6];

        println!("2 in array1: {}", array1.iter().any(|&x| x == 2));
        println!("2 in array2: {}", array2.iter().any(|&x| x == 2));
        println!("Find 2 in array1: {:?}", array1.iter().find(|&&x| x == 2));
        println!(
            "Find 2 in array2: {:?}",
            array2.into_iter().find(|&x| x == 2)
        );

        // 高阶函数

        {
            fn is_odd(n: u32) -> bool {
                n % 2 == 1
            }

            println!("1000以内所有奇数平方和");
            let upper = 1000;

            let mut acc = 0;

            for n in 0.. {
                let n_squared = n * n;

                if n_squared >= upper {
                    // Break
                    break;
                } else if is_odd(n_squared) {
                    acc += n_squared;
                }
            }
            println!("通用式: {}", acc);

            let sum_of_squared_odd_numbers: u32 = (0..)
                .map(|n| n * n)
                .take_while(|&n_squared| n_squared < upper)
                .filter(|&n_squared| is_odd(n_squared))
                .fold(0, |acc, n_squared| acc + n_squared);
            println!("函数式: {}", sum_of_squared_odd_numbers);
        }
    }

    // ！ 永远不会返回， loop{} -> !
    #[allow(dead_code)]
    fn foo() -> ! {
        panic!("This call never returns.");
    }

}
